﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using Provausio.Server.Nzb.Poller.Data.Source;
using Provausio.Server.Nzb.Poller.Object.Domain;

namespace Provausio.Server.Nzb.Poller.Logic
{
    public class PollServicesOperation
    {
        private static readonly int NotificationIntervalHours =
            Convert.ToInt32(ConfigurationManager.AppSettings["NotificationIntervalHours"]);
        private readonly Dictionary<Services, PingApiOperationBase> _services;
        private static readonly Dictionary<Services, DateTime> Notified;

        static PollServicesOperation()
        {
            Notified = new Dictionary<Services, DateTime>();
        }

        public PollServicesOperation()
        {
            _services = new Dictionary<Services, PingApiOperationBase>
            {
                {Services.Sickbeard, new SickbeardPingSource()},
                {Services.SABNzbd, new SabNzbdPingSource()},
                {Services.CouchPotato, new CouchPotatoPingSource()}
            };
        }

        public void PollServices()
        {
            try
            {
                GenericLogger.WriteLog("###Beginning Poll");
                CleanupNotifiedQueue();

                // if any of the services are down, notify user
                var failed = new List<string>();
                var failedServices = new List<Services>();
                foreach (var service in _services
                    .AsParallel()
                    .Where(service => !service.Value.IsAlive() && !Notified.ContainsKey(service.Key)))
                {
                    failed.Add(service.Value.ServiceName);
                    failedServices.Add(service.Key);

                    // track that a notification was sent
                    Notified.Add(service.Key, DateTime.Now);
                }

                if (failed.Count <= 0) return;

                LogFailure(failedServices);
                new NotifyServiceDownOperation().Notify(failed);
            }
            finally
            {
                GenericLogger.WriteLog("###Poll Completed");
            }
        }

        private static void CleanupNotifiedQueue()
        {
            foreach (var notification in Notified)
            {
                if ((DateTime.Now - notification.Value).Hours >= NotificationIntervalHours)
                {
                    Notified.Remove(notification.Key);
                }
            }
        }

        private static void LogFailure(IEnumerable<Services> service)
        {
            var failed = (from s in service where Notified.ContainsKey(s) select s.ToString()).ToList();

            GenericLogger.WriteLog(string.Format("INFO: {0} have/has failed but the user has already been notified.", string.Join(",", failed)));
        }
    }
}
